//=============================================
// Function  : Synchronous (single clock) FIFO
// Coder     : Deepak Kumar Tala
// Date      : 31-October-2005
//=============================================
module syn_fifo #(parameter DATA_WIDTH = 8,
                  parameter ADDR_WIDTH = 8,
                  parameter RAM_DEPTH = (1 << ADDR_WIDTH))(
input   wire                  clk      , // Clock input
input   wire                  rst      , // Active high reset
input   wire                  wr_cs    , // Write chip select
input   wire                  rd_cs    , // Read chipe select
input   wire [DATA_WIDTH-1:0] data_in  , // Data input
input   wire                  rd_en    , // Read enable
input   wire                  wr_en    , // Write Enable
output  reg  [DATA_WIDTH-1:0] data_out , // Data Output
output  wire                  empty    , // FIFO empty
output  wire                  full       // FIFO full
);    
//-----------Internal variables-------------------
reg [ADDR_WIDTH-1:0] wr_pointer;
reg [ADDR_WIDTH-1:0] rd_pointer;
reg [ADDR_WIDTH :0] status_cnt;
wire [DATA_WIDTH-1:0] data_ram ;
//-----------Variable assignments---------------
assign full = (status_cnt == (RAM_DEPTH-1));
assign empty = (status_cnt == 0);
//-----------Code Start---------------------------
always_ff @ (posedge clk iff rst == 0 , posedge rst)
begin : WRITE_POINTER
  if (rst) begin
    wr_pointer <= 0;
  end else if (wr_cs && wr_en ) begin
    wr_pointer <= wr_pointer + 1;
  end
end

always_ff @ (posedge clk iff rst == 0 , posedge rst)
begin : READ_POINTER
  if (rst) begin
    rd_pointer <= 0;
  end else if (rd_cs && rd_en ) begin
    rd_pointer <= rd_pointer + 1;
  end
end

always_ff  @ (posedge clk iff rst == 0 , posedge rst)
begin : READ_DATA
  if (rst) begin
    data_out <= 0;
  end else if (rd_cs && rd_en ) begin
    data_out <= data_ram;
  end
end

always_ff @ (posedge clk iff rst == 0 , posedge rst)
begin : STATUS_COUNTER
  if (rst) begin
    status_cnt <= 0;
  // Read but no write.
  end else if ((rd_cs && rd_en) && !(wr_cs && wr_en) 
                && (status_cnt != 0)) begin
    status_cnt <= status_cnt - 1;
  // Write but no read.
  end else if ((wr_cs && wr_en) && !(rd_cs && rd_en) 
               && (status_cnt != RAM_DEPTH)) begin
    status_cnt <= status_cnt + 1;
  end
end 
   
ram_dp_ar_aw #(DATA_WIDTH,ADDR_WIDTH)DP_RAM (
.address_0 (wr_pointer) , // address_0 input 
.data_0    (data_in)    , // data_0 bi-directional
.cs_0      (wr_cs)      , // chip select
.we_0      (wr_en)      , // write enable
.oe_0      (1'b0)       , // output enable
.address_1 (rd_pointer) , // address_q input
.data_1    (data_ram)   , // data_1 bi-directional
.cs_1      (rd_cs)      , // chip select
.we_1      (1'b0)       , // Read enable
.oe_1      (rd_en)        // output enable
);     

endmodule
